﻿
package extremefx.ui {
	import extremefx.events.EventArgs;
	import extremefx.geom.Edge;
	import extremefx.geom.Size;
	import extremefx.ui.UIComponent;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.ui.Keyboard;	

	/**
	 * @author Marcelo Volmaro
	 */
	public class ScrollPane extends UIComponent {
		public static const CACHE:uint = 1; 
		
		public static const HSB_AUTO:uint = 2; 
		public static const HSB_ON:uint = 4; 
		public static const HSB_OFF:uint = 8; 
		
		public static const VSB_AUTO:uint = 16; 
		public static const VSB_ON:uint = 32; 
		public static const VSB_OFF:uint = 64;
		
		private var _vScrollBar:VScrollBar;
		private var _hScrollBar:HScrollBar;
		private var _contents:DisplayObject;
		private var _cWidth:uint;
		private var _cHeight:uint;
		private var _mask:Rectangle;
		private var _cAsBmp:Boolean;
		private var _hsvv:int;
		private var _vsvv:int;
		private var _refresh:Boolean;
//		private var _opaque:Color;
		
		private var _tempScrollH:int;
		private var _tempScrollV:int;
		private var _setScrollH:Boolean;
		private var _setScrollV:Boolean;
		private var _keyHandler:Boolean;
		private var _lastMX:int;
		private var _lastMY:int;
		private var _easyScroll:Boolean;

		public function ScrollPane(pParameters:UIParameters = null, pOptions:uint = 36) {
			super();
			
			pParameters = initStyle("ScrollPane", pParameters);
			pParameters._parent = this;
			
			_visualUI.addEventListener(MouseEvent.MOUSE_DOWN, _myFocusIn, false, 0, true);
			_cAsBmp = (pOptions & CACHE) != 0;

			_hsvv = (pOptions & HSB_OFF) ? 0 : (pOptions & HSB_ON) ? 1 : -1;  
			_vsvv = (pOptions & VSB_OFF) ? 0 : (pOptions & VSB_ON) ? 1 : -1;  
			
			if (_hsvv){
				var hsb:HScrollBar = _hScrollBar = new HScrollBar(pParameters);
				hsb.focusable(false);
				hsb.onScroll.add(_onScroll);
				hsb.onStartDrag.add(_onStartDrag);
				hsb.onStopDrag.add(_onStopDrag);
				hsb.useMouseWheel = false;
				_mSprite.addChild(hsb._visualUI);
			}
			
			if (_vsvv){
				var vsb:VScrollBar = _vScrollBar = new VScrollBar(pParameters);
				vsb.focusable(false);
				vsb.onScroll.add(_onScroll);
				vsb.onStartDrag.add(_onStartDrag);
				vsb.onStopDrag.add(_onStopDrag);
				vsb.useMouseWheel = true;
				_mSprite.addChild(vsb._visualUI);
			}
		}
		
		private function _onScroll(pSender:ScrollBar, pArgs:EventArgs):void {
			var m:Rectangle = _mask;
			
			if (pSender is HScrollBar){
				m.x = pSender.scrollPosition; 
								
			} else {
				m.y = pSender.scrollPosition;
			}
			
			_contents.scrollRect = m;
		}

		private function _onStopDrag(pSender:ScrollBar, pArgs:EventArgs):void {
			if (_cAsBmp) _contents.cacheAsBitmap = false;
		}

		private function _onStartDrag(pSender:ScrollBar, pArgs:EventArgs):void {
			focus();
			if (_cAsBmp) _contents.cacheAsBitmap = true;
		}

		public function get useMouseWheel():Boolean {
			return _vScrollBar ? _vScrollBar.useMouseWheel : false;
		}
		
		public function set useMouseWheel(pUseWheel:Boolean):void {
			if (_vScrollBar) _vScrollBar.useMouseWheel = pUseWheel;
		}
		
		public function get content():DisplayObject {
			return _contents;
		}
		
		public function set content(pContents:DisplayObject):void {
			if (_contents){
				_mSprite.removeChild(_contents);
			}
			
			if (!pContents){
				pContents = new Sprite();
			}
			
			_contents = pContents;
			_mSprite.addChildAt(pContents, 0);
			pContents.scrollRect = _mask;

			refresh();
		}
		
		public function refresh():void {
			_refresh = true;
			invalidate();
		}
		
		private function _myFocusIn(pE:MouseEvent):void {
			focus();
		}
		
		override public function focus():void {
			super.focus();
			if (_vScrollBar) _vScrollBar.focus();
			if (_hScrollBar) _hScrollBar.focus();
			
			if (_easyScroll && (_vScrollBar || _hScrollBar)){
				if (!_keyHandler) {
					KeyHandler.addKeyHandler(Keyboard.CONTROL, _startEasyScroll, _endEasyScroll);
					_keyHandler = true;
				}
			}
		}
		
		public function get easyScroll():Boolean {
			return _easyScroll;
		}
		
		public function set easyScroll(pES:Boolean):void {
			_easyScroll = pES;
			if (!pES){
				_removeES();
			}
		}
		
		private function _startEasyScroll(pSKStatus:uint):void {
			UIStage.addEventListener(MouseEvent.MOUSE_DOWN, _startES2);
			UIStage.addEventListener(MouseEvent.MOUSE_UP, _endES2);
		}
		
		private function _startES2(pE:MouseEvent):void {
			_visualUI.addEventListener(MouseEvent.MOUSE_MOVE, _doEasyScroll, false, 0, true);
			_lastMX = UIStage.mouseX;
			_lastMY = UIStage.mouseY;
		}
		
		private function _endES2(pE:MouseEvent):void {
			_visualUI.removeEventListener(MouseEvent.MOUSE_MOVE, _doEasyScroll);
		}
		
		private function _endEasyScroll(pSKStatus:uint):void {
			UIStage.removeEventListener(MouseEvent.MOUSE_DOWN, _startES2);
			UIStage.removeEventListener(MouseEvent.MOUSE_UP, _endES2);
		}
		
		private function _doEasyScroll(pE:MouseEvent):void {
			var mx:int = UIStage.mouseX;
			var my:int = UIStage.mouseY;
			
			if (_vScrollBar) _vScrollBar.thumbPosition += (my - _lastMY);
			if (_hScrollBar) _hScrollBar.thumbPosition += (mx - _lastMX);
			
			_lastMX = mx;
			_lastMY = my;
		}
		
		override public function blur():void {
			super.blur();
			if (_vScrollBar) _vScrollBar.blur();
			if (_hScrollBar) _hScrollBar.blur();
			_removeES();
		}
		
		private function _removeES():void {
			if (_keyHandler) {
				KeyHandler.removeKeyHandler(Keyboard.CONTROL, _startEasyScroll, _endEasyScroll);
				_endES2(null);
				_endEasyScroll(0);
				_keyHandler = false;
			}
		}
		
		override public function set enabled(pE:Boolean):void {
			super.enabled = pE;
			if (_vScrollBar) _vScrollBar.enabled = pE;
			if (_hScrollBar) _hScrollBar.enabled = pE;
		}
		
		override protected function _draw():void {
			var p:Edge = _style.padding;
			
			if (_refresh){
				_refresh = false;
				_cWidth = _contents.width;
				_cHeight = _contents.height;
				_contents.x = p.left;
				_contents.y = p.top;
			}
			
			var oldX:int,
			oldY:int,
			hs:uint = _width,
			vs:uint = _height,
			vsb:Boolean = false,
			hsb:Boolean = false,
			cw:uint = _cWidth - hs,
			ch:uint = _cWidth - vs,
			vsbX:uint = hs,
			hsbY:uint = vs;
			
			if (_setScrollH){
				oldX = _tempScrollH;
				_setScrollH = false;
				
			} else {
				oldX = scrollH;
			}
			
			if (_setScrollV){
				oldY = _tempScrollV;
				_setScrollV = false;
				
			} else {
				oldY = scrollV;
			}
		
			if (_vScrollBar){
				vsb = true;
				var vsbw:uint = _vScrollBar.width,
				vsbp:Edge = _vScrollBar.computedStyle.position;
				
				_vScrollBar.position = new Point(vsbX = hs - vsbw - vsbp.right, vsbp.top);
				_vScrollBar.size = new Size(0, vsbp.getHeight(vs));
				
				if (_vsvv){//on
					hs -= vsbw;
					cw += vsbw;
					
				} else {//auto
					if (ch > 0){
						hs -= vsbw;
						cw += vsbw;

					} else {
						vsb = false;
					}
				}
			}
			
			if (_hScrollBar){
				var hsbh:uint = _hScrollBar.height,
				hsbp:Edge = _hScrollBar.computedStyle.position;
				_hScrollBar.position = new Point(hsbp.left, hsbY = vs - hsbh - hsbp.bottom);
				
				hsb = true;
				
				if (_hsvv){//on
					vs -= hsbh;
					ch += hsbh;
					
				} else {//auto
					if (cw > 0){
						vs -= hsbh;
						ch += hsbh;
	
						if (ch > 0){
							if (!vsb){
								hs -= vsbw;
								cw += vsbw;
								vsb = true;
							}
	
						} else {
							vsb = false;
						}
	
					} else {
						hsb = false;
					}
				}
				
				_hScrollBar.size = new Size(hsbp.getWidth(hs), 0);
			}
			
			if (_hScrollBar) {
				_hScrollBar.visible = hsb;
				_hScrollBar.setScrollProperties(hs, 0, cw + p.left + p.right);
			}
			
			if (_vScrollBar) {
				_vScrollBar.visible = vsb;
				_vScrollBar.setScrollProperties(vs, 0, ch + p.top + p.bottom);
			}
			
			_drawBBox(_visualUI, 0, 0, vsbX, hsbY);
			
			_mask = new Rectangle(oldX, oldY, p.getWidth(vsbX), p.getHeight(hsbY));
			_contents.scrollRect = _mask;
			
			_setDecoState(1, _width, _height);
		}
		
		override internal function setKeyEnabled(pK:Boolean):void {
			super.setKeyEnabled(pK);
			if (_vScrollBar) _vScrollBar.setKeyEnabled(pK);
			if (_hScrollBar) _hScrollBar.setKeyEnabled(pK);
		}
		
		override public function get preferredSize():Size {
			return new Size(_cWidth, _cHeight);
		}

//		override public function get minimumSize():Size {
//			return preferredSize;
//		}

		override public function dispose():void {
			if (_disposing) return;
			super.dispose();
			
			content = null;
			
			if (_vScrollBar) _vScrollBar.dispose();
			if (_hScrollBar) _hScrollBar.dispose();
			
			_visualUI.removeEventListener(MouseEvent.MOUSE_DOWN, _myFocusIn);
		}
		
		public function get scrollH():int {
			return _hScrollBar ? _hScrollBar.scrollPosition : 0;
		}
		
		public function get scrollV():int {
			return _vScrollBar ? _vScrollBar.scrollPosition : 0;
		}
		
		public function set scrollH(pPos:int):void {
			if (_refresh){
				_setScrollH = true;
				_tempScrollH = pPos;
				
			} else if (_hScrollBar){
				_hScrollBar.scrollPosition = pPos;
			}
		}
		
		public function set scrollV(pPos:int):void {
			if (_refresh){
				_setScrollV = true;
				_tempScrollV = pPos;
				
			} else if (_vScrollBar){
				_vScrollBar.scrollPosition = pPos;
			}
		}
	}
}
